package com.wjh.ioc;

import com.wjh.DI.DI;
import com.wjh.anno.*;
import javafx.beans.binding.ObjectExpression;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

// spring上下文
public class RAnnotationConfigurationApplicationContext {
    //储存获取到的class对象，因为不能重复，所以用hashset
    private Set<Class> clazzSet = new HashSet<>();
    //存储实例对象
     private Map<Class<?>,Object> beanMap = new ConcurrentHashMap<>();

     //维护一个list集合，存储所有bean集合
    private List<Class<?>> list = new ArrayList<>();

    public RAnnotationConfigurationApplicationContext(Class<?> componentClasses){
    //判断传进来的类是不是配置类
        if(!componentClasses.isAnnotationPresent(HConfiguration.class)){//看传进来的是否有HConfiguration注解
            throw  new RuntimeException(componentClasses+"is not HConfiguration class");
        }
//获取@HcomponentScan注解的内容
        HComponentScan hComponentScan = componentClasses.getAnnotation(HComponentScan.class);
        String basePackage = hComponentScan.basePackage();
        System.out.println(basePackage);
        //通过部分路径获取全路径
        URL url = Thread.currentThread().getContextClassLoader().getResource(basePackage.replace(".","/"));
//        System.out.println(url);
        if(url == null){
            throw new RuntimeException("can't get url,please check...");
        }
        File file  =new File(url.getPath());
        //迭代当前目录，即把扫描路径的子目录也扫描
        recursionFile1(file,basePackage);
        new DI(clazzSet,beanMap);
//        System.out.println(beanMap);

        //依赖注入操作
      /*  for(Class<?> clazz:list){

            Field[] fields = clazz.getDeclaredFields();
         
            if(fields == null) continue;
            for(Field field :fields){

                //如果有该注解，则进行注入对象实例
                if(field.isAnnotationPresent(HAutowired.class)){

                 //1.先获取类型
                 Class<?> fieldType = field.getType();

                 //2.从IOC容器中查找有对应的bean或者子类或实现类
                    Object fieldBean = beanMap.get(fieldType);
                    if(fieldBean == null){
                        Set<Class<?>> resultSet = getClassesBySuperOrInterface(fieldType);
                        fieldBean = resultSet.iterator().next();

                        //进行赋值
                        field.setAccessible(true);
                        try{
                            field.set(beanMap.get(clazz),beanMap.get(fieldBean));
                        }
                        catch (IllegalAccessException e){
                            e.printStackTrace();
                        }


                    }
                }
            }
        }*/

    }
//
//    private Set<Class<?>> getClassesBySuperOrInterface(Class<?> fieldType) {
//       Set<Class<?>> classSet = new HashSet<>();
//        for(Class<?> clazz :list){
//            //判断是不是子类或者实现类
//            if (fieldType.isAssignableFrom(clazz) && !clazz.equals(fieldType)){
//                classSet.add(clazz);
//            }
//        }
//        return classSet;
//    }

    //从一个文件路径递归搜索
    private void recursionFile1(File file, String basePackage) {

        File[] files = file.listFiles();//获取当前目录的所有文件
        if(files != null){
            for (int i = 0; i < files.length; i++){
                File absoluteFile = files[i].getAbsoluteFile();
                if(absoluteFile.isDirectory()){
                    recursionFile1(absoluteFile,basePackage); //是文件夹，则继续迭代
                }
                else if(absoluteFile.toString().endsWith(".class")){ //是文件则判断是否是class文件
                    //File.separator  与系统有关的默认名称分隔符，它被表示为一个字符串。此字符串只包含一个字符 即/ 或\
                        String temp = absoluteFile.toString().replace(File.separator,".");
                        //substring  返回一个新的字符串，它是此字符串的一个子字符串。
                        String className = temp.substring(temp.indexOf(basePackage));//com.controller.UserController.class
                        className = className.substring(0,className.lastIndexOf("."));//com.controller.UserController
                    System.out.println("className::"+className);
                    try{
                      Class<?> clazz =   Class.forName(className);//获取class对象
                        //判断该对象是否因该加入容器，即是否有相应注解
                        if(clazz.isAnnotationPresent(HComponent.class) ||clazz.isAnnotationPresent(HController.class)
                        || clazz.isAnnotationPresent(HService.class) || clazz.isAnnotationPresent(HRepository.class)){
                            clazzSet.add(clazz);
                            list.add(clazz);
                           // 创建对象
                            try{
                                Constructor<?> constructor = clazz.getDeclaredConstructor();
                                Object o = constructor.newInstance();
                                beanMap.put(clazz,o);
                            }
                            catch (Exception e){

                            }

                        }

                    }
                    catch (ClassNotFoundException e){
                        e.printStackTrace();
                    }
                    }
            }
        }
    }
    //返回所有class对象
     public List<Class<?>> getBeanDefinitionNames(){
        return list;
     }
     public Object getBean(Class<?> clazz){
        return beanMap.get(clazz);
     }

}
